﻿import de.back2dos.as24x.xXMLList;
/**
 * an object that supports e4x-ish access.
 * use $name to read attributes and set$name(value) to write attributes.
 */
dynamic class de.back2dos.as24x.xXML {
	//{ region private vars
		private var _attributes:Object;
		private var _children:xXMLList;
		private var _nodeName:String;
		private var _parent:xXML;
		private var _text:String;
	//} endregion
	public function xXML() {
		this._attributes = { };
		this._parent = null;
		this._text = null;
		this._nodeName = null;
		this._children = xXMLList["create"]([]);
	}
	public function removeChild(child:xXML):Boolean {
		var children:Array = this._children["_entries"];
		var length:Number = children.length;
		for (var i:Number = 0; i < length; i++) 
			if (children[i] == child) {
				children.splice(i, 1);
				child._parent = null;
				return true;
			}
		return false;
	}
	public function appendChild(child:xXML):xXML {
		if (child._parent != null) child._parent.removeChild(child);
		this._children["_entries"].push(child);
		child._parent = this;
		return child;
	}
	private function __resolve(prop:String):Object {
		if (prop.charAt(0) == "$") return this._attributes[prop.substr(1)];
		if (prop.substr(0, 4) == "set$") {
			var attr:Object = this._attributes;
			prop = prop.substr(4);
			return function (value:Object):Object { return attr[prop] = value; };
		}
		return this._children[prop];
	}
	//{ region accessors
		/**
		 * the nodes name. null implies text nodes. sort of. :)
		 */
		public function get nodeName():String { return _nodeName; }
		public function set nodeName(value:String):Void { _nodeName = value; }
		/**
		 * the nodes parent
		 */
		public function get parent():xXML { return _parent; }
		/**
		 * the attributes. note: you may access attributes for reading with $name, but writing requires access to this object
		 */
		public function get attributes():Object { return _attributes; }
		/**
		 * children
		 */
		public function get children():xXMLList { return _children; }
		/**
		 * will return the text for textnodes
		 */
		public function get text():String { return _text; }
	//} endregion
	//{ region static constructors
		public static function fromString(source:String):xXML {
			var x:XML = new XML();
			x.ignoreWhite = true;
			x.parseXML(source);
			return xXML.fromNode(x.firstChild);
		}
		public static function fromNode(source:XMLNode):xXML {
			var ret:xXML = new xXML();
			if (source.nodeType == 3) ret._text = source.nodeValue
			else {
				ret._nodeName = source.nodeName;
				var attr:Object = source.attributes;
				for (var name:String in attr) 
					ret._attributes[name] = attr[name];
				
				var children:Array = source.childNodes;
				var len:Number = children.length;
				for (var i:Number = 0; i < len; i++) {
					ret.appendChild(xXML.fromNode(children[i]));
				}
			}			
			return ret;
		}
		/**
		 * 
		 * @param	url the url where to load the xXML from
		 * @param	onComplete a Function, that will take the loaded and parsed xXML as parameter
		 * @param	onFail a Function, that will take the url as parameter, where load operation failed
		 */
		public static function fromURL(url:String, onComplete:Function, onFail:Function):Void {
			var l:LoadVars = new LoadVars();
			l.load(url);
			l.onData = function (source:String):Void {
				if (source == undefined) onFail(url);
				else onComplete(xXML.fromString(source));
			}
		}
	//} endregion
	public function toString():String {
		return "[object xXML]";
	}
}